package com.gxa.learning.pc.service.impl;

import com.gxa.learning.core.common.ExceptionCode;
import com.gxa.learning.core.exception.BusinessException;
import com.gxa.learning.core.pojo.Project;
import com.gxa.learning.core.pojo.ProjectApply;
import com.gxa.learning.core.pojo.ProjectSign;
import com.gxa.learning.core.pojo.User;
import com.gxa.learning.core.service.impl.BaseServiceImpl;
import com.gxa.learning.core.util.StringUtil;
import com.gxa.learning.pc.mapper.ProjectApplyMapper;
import com.gxa.learning.pc.mapper.ProjectMapper;
import com.gxa.learning.pc.mapper.ProjectSignMapper;
import com.gxa.learning.pc.mapper.UserMapper;
import com.gxa.learning.pc.service.ProjectSignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Transactional(rollbackFor = Throwable.class)
public class ProjectSignServiceImpl extends BaseServiceImpl<ProjectSign> implements ProjectSignService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate = null;

    @Autowired
    private ProjectMapper projectMapper = null;

    @Autowired
    private UserMapper userMapper = null;

    @Autowired
    private ProjectSignMapper projectSignMapper = null;

    @Autowired
    private ProjectApplyMapper projectApplyMapper = null;


    //设置常量来拼接做redis的键
    public static final String SIGN_KEY = "AND_SOCK_SIGN_KEY:";
    //保证让同一个人停止自己的签到
    public static final String USER_IS = "THE_USER_IS:";

    @Override
    public void sendSignIn(Long pid, Long uid) throws BusinessException {
        if (pid == null || pid == 0) {
            throw new BusinessException(ExceptionCode.WRONG_OPTION);
        }
        //查询是否有当前的培训项目
        Project project = projectMapper.selectByPrimaryKey(pid);
        if (project == null) {
            throw new BusinessException(ExceptionCode.NO_SUCH_OBJ);
        }
        ValueOperations<String, Object> stringOps = redisTemplate.opsForValue();
        //生成一个UUID用来表示不同的签到
        String value = UUID.randomUUID().toString();
        value = value.replaceAll("-", "");
        //保证让同一个人停止自己的签到
        Boolean isOk = stringOps.setIfAbsent(USER_IS + uid + SIGN_KEY + pid, value, 20, TimeUnit.MINUTES);
        //设置签到的键值
        stringOps.setIfAbsent(SIGN_KEY+pid,value);
        if (!isOk) {
            throw new BusinessException(ExceptionCode.HAS_SAME_SIGN);
        }
        //添加所有学员到签到表，并把所有这次签到的状态置为false
        //获取所有这个项目的学员
        List<Long> nums = projectSignMapper.getNotSignNum(pid);
        if (nums == null) {
            redisTemplate.delete(USER_IS + uid + SIGN_KEY + pid);
            redisTemplate.delete(SIGN_KEY+pid);
            throw new BusinessException(ExceptionCode.HAS_NO_STUDENTS);
        }
        Date date = new Date(System.currentTimeMillis());
        ArrayList<ProjectSign> projectSigns = new ArrayList<>();
        //添加所有学员到签到表
        for (Long num : nums) {
            ProjectSign projectSign = new ProjectSign();
            projectSign.setSignKey(value);
            projectSign.setProjectId(pid);
            projectSign.setUserId(num);
            projectSign.setTime(date);
            projectSign.setStatus(false);
            projectSigns.add(projectSign);
        }
        //判断集合中是否有元素
        if (projectSigns.size() == 0) {
            redisTemplate.delete(USER_IS + uid + SIGN_KEY + pid);
            redisTemplate.delete(value);
            throw new BusinessException(ExceptionCode.HAS_NO_STUDENTS);
        }
        Integer integer = projectSignMapper.addNoSign(projectSigns);
        if (integer < 1) {
            throw new BusinessException(ExceptionCode.INVALID_OPERATION);
        }
    }

    @Override
    public void stopSign(Long pid, Long uid) throws BusinessException {
        if (pid == null || pid <= 0 || uid == null || uid <= 0) {
            throw new BusinessException(ExceptionCode.WRONG_OPTION);
        }
        ValueOperations<String, Object> stringOps = redisTemplate.opsForValue();
        Object o = stringOps.get(USER_IS + uid + SIGN_KEY + pid);
        if (o == null) {
            throw new BusinessException(ExceptionCode.INVALID_OPERATION);
        }
        Boolean delete = redisTemplate.delete(USER_IS + uid + SIGN_KEY + pid);
        redisTemplate.delete(SIGN_KEY + pid);
        if (!delete) {
            throw new BusinessException(ExceptionCode.FAILED_OPTION);
        }
    }

    @Override
    public String haveCheckSign(Long pid, Long uid) throws BusinessException {
        if (pid == null || uid == null) {
            throw new BusinessException(ExceptionCode.ARGUMENTS_ERROR);
        }
        Example userExample = new Example(User.class);
        Example.Criteria userCriteria = userExample.createCriteria();
        userCriteria.andEqualTo("id", uid);
        User user = userMapper.selectOneByExample(userExample);
        if (user == null) {
            throw new BusinessException(ExceptionCode.INVALID_OPERATION);
        }
        Project project = projectMapper.selectByPrimaryKey(pid);
        if (project == null) {
            throw new BusinessException(ExceptionCode.INVALID_OPERATION);
        }
        //判断用户是不是培训项目的学员
        ProjectApply projectApply = new ProjectApply();
        projectApply.setUserId(uid);
        projectApply.setProjectId(pid);
        projectApply.setApplyStatus(1);
        ProjectApply apply = projectApplyMapper.selectOne(projectApply);
        if (apply == null) {
            throw new BusinessException(ExceptionCode.IS_NOT_A_STUDENT);
        }
        ValueOperations<String, Object> stringOps = redisTemplate.opsForValue();
        Object o = stringOps.get(SIGN_KEY+pid);
        if (o != null) {
            return (String)o;
        } else {
            return null;
        }

    }

    @Override
    public void signIn(Long pid, Long uid, String key) throws BusinessException {
        if (pid == null || uid == null || StringUtil.isEmpty(key)) {
            throw new BusinessException(ExceptionCode.ARGUMENTS_ERROR);
        }
        ProjectSign projectSign = new ProjectSign();
        projectSign.setUserId(uid);
        projectSign.setProjectId(pid);
        projectSign.setSignKey(key);
        Example example = new Example(ProjectSign.class);
        Example.Criteria select = example.createCriteria();
        select.andEqualTo("signKey", key);
        select.andEqualTo("userId", uid);
        select.andEqualTo("projectId", pid);
        ProjectSign isHave = projectSignMapper.selectOneByExample(example);
        if (isHave == null) {
            throw new BusinessException(ExceptionCode.ID_WRONG);
        }
        if (isHave.getStatus()) {
            throw new BusinessException(ExceptionCode.HAD_SIGN_IN);
        }
        projectSign.setSignInId(isHave.getSignInId());
        projectSign.setStatus(true);
        projectSign.setSignTime(new Date());
        projectSignMapper.update(projectSign);
    }

    @Override
    public List<Map<String, Object>> getSignInList(String name, Integer page, Integer size, Long pid, Date start, Date end) throws BusinessException {
        if (pid == null) {
            throw new BusinessException(ExceptionCode.ARGUMENTS_ERROR);
        }
        if (page == null || page <= 0) {
            page = 1;
        }
        if (size == null || size <= 0) {
            size = 5;
        }
        if (start == null) {
            end = null;
        }
        if (end == null) {
            start = null;
        }
        Integer offset = (page - 1) * size;
        List<Map<String, Object>> signInList = projectSignMapper.getSignInList(name, offset, size, pid, start, end);
        if (signInList == null || signInList.size() == 0) {
            throw new BusinessException(ExceptionCode.WRONG_DATA);
        }
        return signInList;
    }

    @Override
    public List<Map<String, Object>> getAllSignInList(String name, Long pid) throws BusinessException {
        if (pid == null || pid <= 0) {
            throw new BusinessException(ExceptionCode.ARGUMENTS_ERROR);
        }
        List<Map<String, Object>> signInList = projectSignMapper.getSignInList(name, null, null, pid, null, null);
        if (signInList == null || signInList.size() == 0) {
            throw new BusinessException(ExceptionCode.WRONG_DATA);
        }
        return signInList;
    }

    @Override
    public Boolean isSendSign(Long uid, Long pid) throws BusinessException {
        if (uid == null || uid <= 0 || pid == null || pid <= 0) {
            throw new BusinessException(ExceptionCode.ARGUMENTS_ERROR);
        }
        ValueOperations<String, Object> stringOps = redisTemplate.opsForValue();
        Object o = stringOps.get(USER_IS + uid + SIGN_KEY + pid);
        return o != null;
    }

    @Override
    public List<Map<String, Object>> getMySignList(Long pid, Long uid) throws BusinessException {
        if (pid == null || uid == null || pid <= 0 || uid <= 0) {
            throw new BusinessException(ExceptionCode.ARGUMENTS_ERROR);
        }
        List<Map<String, Object>> mySignList = projectSignMapper.getMySignList(pid, uid);
        if (mySignList == null || mySignList.size() <= 0) {
            throw new BusinessException(ExceptionCode.WRONG_DATA);
        }
        return mySignList;
    }
}
